package tld.course.lesson0 
{
	// Importing several classes we will need in the code that comes later.
	// `import' is the compile time directive, it instructs the compiler how it
	// should resolve the identifiers to the values. Identifier is the program
	// data, which is not a reserved word (usually written by you or another 
	// programmer). For example, later in the code we extend a class from 
	// `Sprite'. When analyzing that code, the compiler should resolve `Sprite'
	// identifier in order to know what methods and properties are available for 
	// use in the class being declared.
	// Also note that `flash.display.Sprite' is called a fully qualified name
	// of the class, while `Sprite' is the class' name. Essentially, the fully
	// qualified name should be spelled as `namespace::ClassName', however, for
	// historic reasons (borrowed from AS2), the fully qualified names may
	// be spelled using property access operator, instead of namespace member 
	// access operator (the `::'). Another possible reason is that the namespace
	// would be evaluated as a series of applications of property access operator
	// instead of being treated as a single body. However, both examples below
	// designate the same class:
	// 		namespace display = "flash.display";
	// 1).
	// 		display::Sprite;
	// 2).
	//		flash.display.Sprite;
	import flash.display.Sprite;
	import flash.events.Event;
	
	/**
	 * An example of basic programmatic drawing for my AS3 class, second lesson.
	 * 
	 * HOMEWORK:
	 * 		- Modify this program in a way it only draws black circles.
	 * 		- Modify this program in a way it draws squares instead of circles.
	 * 		- Modify this program in a way it draws both rectangles and circles.
	 * 		- Bonus points, modify this program in a way it handles collisions
	 * 		  more precisely. That is, once possible collision is detected, 
	 * 		  the program places the collided object on the collided surface.
	 * 		  The object only bounces on the next step. For example, a circle
	 * 		  50 pixels of diameter moves 20 pixels a step. This circle is at
	 * 		  X = 100, the colliding surface is at X = 160 (i.e. the circle 
	 * 		  would have to move only 10 pixels on the next step, instead of
	 * 		  the defined 20).
	 * 
	 * @author wvxvw
	 * 
	 * @flashplayerversion 10.0
	 */
	
	// We declare a class `BouncingCircles' we also extend it from 
	// `flash.display::Sprite'. By extending we add all methods and properties
	// (except if they are static) to the extending class from sthe superclass 
	// (the extended). Depending on the access modifier used in the superclass
	// those properties may or may not be accessible to the code of the 
	// extending class. For example, you cannot access a property declared as
	// `private' in the superclass.
	public class BouncingCircles extends Sprite
	{
		// Declaring a private constant of type `Vector.<Circle>' called 
		// `_circles' and initialize it to the value of an empty vector of 
		// `Circle'-s.
		private const _circles:Vector.<Circle> = new <Circle>[];
		
		// Declaring the constructor of the `BouncingCircles' class. 
		// The constructor is the function with the name same as the class it is
		// the constructor for. This function is automatically called when 
		// creating instances of the class using `new' operator.
		public function BouncingCircles() 
		{
			// Invoking superclass' constructor
			super();
			// Applying an operator `.' to `this' (a compiler created variable
			// that contains a reference of the object created by this class'
			// constructor) and `init' (an identifier). The full stop operator
			// will thus search for a class field called `init' on `this' object.
			// Assume the class field found by full stop operator is callable
			// and apply parenthesis operator - this means we are instructing
			// the runtime to execute the code in the `this.init'.
			this.init();
		}
		
		// Declaring a private method of the `BouncingCircles' class. This 
		// method, unlike constructor, is typed to `void' (in other words, it
		// returns nothing). `:', the colon operator is also called a type 
		// operator is used to declare the type of it's first operand.
		private function init():void
		{
			// Calling `addEventListener', a method of the superclass, providing
			// it two arguments, a constant declared in `Event' class and a
			// function declared in this class.
			// Note that static constants are upper case by convention.
			super.addEventListener(Event.ENTER_FRAME, this.step);
			this.populate(100);
		}
		
		private function populate(count:uint):void
		{
			// Declaring local variables and assigning initial values to some of 
			// them. The asterisk symbol is the multiplication operator, it 
			// calculates the multiple of the first and the second operands and
			// returns it.
			var circle:Circle;
			var middleX:uint = super.stage.stageWidth * 0.5;
			var middleY:uint = super.stage.stageHeight * 0.5;
			
			// In other words, removing all elements of the vector.
			this._circles.splice(0, this._circles.length);
			// Declaring a loop that will run `count' times.
			while (count--)
			{
				// Creating circles and adding them to the vector. `new' 
				// operator is applied to only one operands that follows it.
				// That operand must evaluate to either class or a function,
				// which is not a method of any class.
				// Plus and minus operators work similarly to multiplication
				// operator. In order to disambugate the priority of execution
				// of actions associated with operators there exist rules for
				// also known as operators precedence. Thise rules, for example
				// have plus and minus have lower priority, so that 
				// multiplication and division would be carried out first.
				// You may override the default rules by wrapping an expressions
				// in parenthesis. For example (10 + 5) * 2 will result in 30
				// while 10 + 5 * 2 will result in 20.
				// The order of application is also influenced by associativity,
				// that is the direction to carry out operations for operators
				// with same priority level. `+' and `-' are right-associative,
				// which means that expression 1 + 2 - 3 + 4 will calculate as 
				// follows:
				// 1 + 2 -> 3
				// 3 - 3 -> 0
				// 0 + 4 -> 4
				// On the other hand, `=', the assignment operator, is 
				// left-associative, so in an expression a = b = c = 42 the order
				// of operations will be exactly opposite:
				// c = 42 -> 42
				// b = 42 -> 42
				// a = 42 -> 42
				// the `->' sign is used here to mean the returned value.
				circle = new Circle(Math.random() * 40 + 10, 
					Math.random() * 0xFFFFFF);
				circle.direction.x = Math.random() * 10 - 20;
				circle.direction.y = Math.random() * 10 - 20;
				circle.x = middleX;
				circle.y = middleY;
				// `as' operator is in a way a runtime analogue of `:' operator,
				// however it will verify the runtime type of the object and
				// substitute `null' for it, if the type of the object doesn't
				// match the type of it's second operand.
				this._circles.push(super.addChild(circle) as Circle);
			}
		}
		
		// This function makes use of a default argument values. Functions are
		// allowed to have default values for arguments with the restriction 
		// that the value must exist at compile time, strings and numbers are
		// said to exist at compile time, likewise Booleans, `null' and 
		// `undefined'.
		private function step(event:Event = null):void
		{
			var diameter:uint;
			
			// Declaring a for-each loop. This loop will iterate over a 
			// collection either an array, vector or dynamic object. When 
			// iterating over an array or vector the loop will step over 
			// elements of an array (not the indices), when iterating over 
			// properties of dynamic object, it will step over values (not the
			// keys).
			for each (var circle:Circle in this._circles)
			{
				diameter = circle.width;
				circle.x = this.calculatePosition(circle.x, circle.direction.x, 
					diameter, super.stage.stageWidth, circle.bounceX);
				circle.y = this.calculatePosition(circle.y, circle.direction.y, 
					diameter, super.stage.stageHeight, circle.bounceY);
			}
		}
		
		private function calculatePosition(position:uint, direction:int, 
			diameter:uint, limit:uint, bounce:Function):uint
		{
			var result:uint = position + direction;
			
			// Conditions are constructed using `if' statement. Note that `||' 
			// and `&&' operators are lazy. In other words, they evaluate the 
			// operands on demand. This means that in an expression `X || Y',
			// `Y' subexpression may not necessary be calculated, it will not be
			// calculated if `X' evaluates to `true'.
			// `<' and `>' are less then and greater then operators, both return
			// Booleans if their operands match the operators rule.
			if (result + diameter > limit || result - diameter < 0)
				result = bounce();
			// `return' is a keyword (same way as `if' is). Every function 
			// returns a value, but it is not necessary to explicitly return
			// if returned value is of type `void' as there is only one value of
			// type `void' - the `undefined', and this is what will be returned
			// if you don't return nothing else.
			return result;
		}
	}
}